package com.ruoyi.app.service.impl

import cn.binarywang.wx.miniapp.api.WxMaService
import cn.hutool.core.util.ObjectUtil
import cn.hutool.core.util.PhoneUtil
import cn.hutool.http.HttpUtil
import com.alibaba.fastjson.JSON
import com.aliyuncs.DefaultAcsClient
import com.aliyuncs.dypnsapi.model.v20170525.GetMobileRequest
import com.aliyuncs.profile.DefaultProfile
import com.baomidou.mybatisplus.extension.kotlin.KtQueryWrapper
import com.baomidou.shaun.core.mgt.SecurityManager
import com.baomidou.shaun.core.profile.TokenProfile
import com.ruoyi.app.common.*
import com.ruoyi.app.domain.dto.*
import com.ruoyi.app.domain.vo.QqLoginResult
import com.ruoyi.app.domain.vo.WxLoginResult
import com.ruoyi.app.service.LoginApiService
import com.ruoyi.back.domain.AppInfo
import com.ruoyi.back.domain.AppUser
import com.ruoyi.back.domain.dto.AppUserDto
import com.ruoyi.back.enums.LoginTypeEnum
import com.ruoyi.back.enums.UserStatusEnum
import com.ruoyi.back.service.AppInfoService
import com.ruoyi.back.service.AppUserService
import com.ruoyi.common.core.redis.RedisCache
import com.ruoyi.config.AliSms
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.stereotype.Service
import java.util.concurrent.TimeUnit

@Service
class LoginApiServiceImpl : LoginApiService {

    @Autowired
    private lateinit var appUserService: AppUserService

    @Autowired
    private lateinit var wxMaService: WxMaService

    @Autowired
    private lateinit var securityManager: SecurityManager

    @Autowired
    private lateinit var redisCache: RedisCache

    @Autowired
    private lateinit var appInfoService: AppInfoService

    @Autowired
    private lateinit var aliSms: AliSms

    override fun phoneLogin(phoneLoginDto: PhoneLoginDto): Data<String> =
        redisCache.getCacheObject<String>(messageRedisKey(phoneLoginDto.phone))?.run {
            ObjectUtil.equals(this, phoneLoginDto.code).takeIf { it }?.run {
                appUserService.getOne(
                    KtQueryWrapper(AppUser::class.java).eq(AppUser::username, phoneLoginDto.phone)
                        .eq(AppUser::loginType, LoginTypeEnum.PHONE.code)
                )
                    ?.run {
                        Ok("手机号登录成功", appUserService.operationUser(
                            AppUserDto(
                                username = phoneLoginDto.phone,
                                source = phoneLoginDto.source,
                                loginType = LoginTypeEnum.PHONE.code,
                                firstInstallationData = phoneLoginDto.firstInstallationData
                            )
                        ).run { tokenGenerator(id!!.toString()) })
                    } ?: Fail(204, "手机号尚未注册")
            } ?: run { Fail(201, "短信验证码不一致!") }
        } ?: kotlin.run { Fail(202, "短信验证码已经失效") }


    override fun register(registerDto: RegisterDto): Data<String> =
        appUserService.getOne(
            KtQueryWrapper(AppUser::class.java)
                .eq(AppUser::username, registerDto.phone)
                .eq(AppUser::loginType, LoginTypeEnum.PHONE.code)
        )
            ?.run {
                Fail(203, "手机号已经注册过")
            }
            ?: kotlin.run {
                redisCache.getCacheObject<String>(messageRedisKey(registerDto.phone!!))?.run {
                    ObjectUtil.equals(this, registerDto.code).takeIf { it }?.run {
                        Ok("手机号注册成功", appUserService.operationUser(
                            AppUserDto(
                                username = registerDto.phone,
                                source = registerDto.source,
                                loginType = LoginTypeEnum.PHONE.code,
                                password = registerDto.password,
                                firstInstallationData = registerDto.firstInstallationData
                            )
                        ).run { tokenGenerator(id!!.toString()) })
                    } ?: run { Fail(201, "短信验证码不一致!") }
                } ?: kotlin.run { Fail(202, "短信验证码已经失效") }
            }

    override fun passwordLogin(phonePasswordLoginDto: PhonePasswordLoginDto): Data<String> =
        appUserService.getOne(
            KtQueryWrapper(AppUser::class.java).eq(AppUser::username, phonePasswordLoginDto.phone)
                .eq(AppUser::loginType, LoginTypeEnum.PHONE.code)
        )
            ?.let {
                return if (it.password == phonePasswordLoginDto.password) {
                    if (it.status == UserStatusEnum.FREEZE.code) Fail("账号已被冻结!")
                    else Ok(
                        "登录成功",
                        kotlin.run {
                            phonePasswordLoginDto.source?.run {
                                appUserService.updateById(it.apply {
                                    source = phonePasswordLoginDto.source
                                    firstInstallationData =
                                        it.firstInstallationData ?: phonePasswordLoginDto.firstInstallationData
                                })
                            }
                            tokenGenerator(it.id!!.toString())
                        }
                    )
                }
                else Fail(205, "密码不一致!")
            } ?: Fail(204, "该手机号尚未注册!")

    override fun forgetPassword(registerDto: RegisterDto): Data<Boolean> =
        appUserService.getOne(
            KtQueryWrapper(AppUser::class.java)
                .eq(AppUser::username, registerDto.phone)
                .eq(AppUser::loginType, LoginTypeEnum.PHONE.code)
        )?.let {
            redisCache.getCacheObject<String>(messageRedisKey(registerDto.phone!!))?.run {
                ObjectUtil.equals(this, registerDto.code).takeIf { it }?.run {
                    Ok("修改密码成功", kotlin.run {
                        appUserService.updateById(it.apply {
                            password = registerDto.password
                        })
                    })
                } ?: run { Fail(201, "短信验证码不一致!") }
            } ?: kotlin.run { Fail(202, "短信验证码已经失效") }
        } ?: Fail(204, "该手机号尚未注册!")

    override fun threeLogin(threeLoginDto: ThreeLoginDto): Data<String> =
        when (threeLoginDto.loginType) {
            1 ->
                HttpUtil.get(weixinInfoUrl(threeLoginDto.access_token!!, threeLoginDto.openid!!)).let { result ->
                    JSON.parseObject(result, WxLoginResult::class.java).run {
                        if (errmsg == null) {
                            appUserService.operationUser(
                                AppUserDto(
                                    username = nickname,
                                    headUrl = headimgurl,
                                    loginType = LoginTypeEnum.WEI_XIN.code,
                                    source = threeLoginDto.source,
                                    openId = this.openid,
                                    firstInstallationData = threeLoginDto.firstInstallationData
                                )
                            ).let { appUser ->
                                if (appUser.status == UserStatusEnum.FREEZE.code) Fail("账号已被冻结")
                                else Ok("微信登陆成功", appUser.run { tokenGenerator(id!!.toString()) })
                            }

                        }
                        else Fail(errmsg!!)
                    }
                }
            else -> HttpUtil.get(qqInfoUrl(threeLoginDto.access_token!!, threeLoginDto.openid!!)).let { result ->
                JSON.parseObject(result, QqLoginResult::class.java).run {
                    if (ret == 0) {

                        appUserService.operationUser(
                            AppUserDto(
                                username = nickname,
                                headUrl = figureurl_qq_1,
                                loginType = LoginTypeEnum.QQ.code,
                                source = threeLoginDto.source,
                                openId = threeLoginDto.openid,
                                firstInstallationData = threeLoginDto.firstInstallationData
                            )
                        ).let { appUser ->
                            if (appUser.status == UserStatusEnum.FREEZE.code) Fail("账号已被冻结")
                            else Ok("QQ登陆成功", appUser.run { tokenGenerator(id!!.toString()) })
                        }
                    }
                    else Fail(msg!!)
                }
            }
        }

    override fun oneKeyLogin(oneKeyLoginDto: OneKeyLoginDto): Data<String> =
        DefaultProfile.getProfile("cn-shanghai", "LTAI5tRQ1acQfyPAnkCWvMAd", "SVVk0Non9jDhpSdISorUnfYZFBqs9c")
            .run {
                DefaultAcsClient(this).getAcsResponse(GetMobileRequest().apply { accessToken = oneKeyLoginDto.token })
                    .let { response ->

                        response.code.takeIf { it == "OK" }?.run {
                            val mobile = response.getMobileResultDTO.mobile
                            appUserService.getOne(
                                KtQueryWrapper(AppUser::class.java).eq(AppUser::username, mobile)
                            )?.run {
                                Ok("手机号一键登陆成功", tokenGenerator(id!!.toString()))
                            } ?: kotlin.run {
                                Ok("手机号一键登录成功", appUserService.operationUser(
                                    AppUserDto(
                                        username = mobile,
                                        source = oneKeyLoginDto.source,
                                        loginType = LoginTypeEnum.PHONE.code,
                                        firstInstallationData = oneKeyLoginDto.firstInstallationData
                                    )
                                ).run { tokenGenerator(id!!.toString()) })
                            }
                        } ?: Fail(response.message)
                    }
            }

    override fun sendSms(phone: String): Data<String> = if (PhoneUtil.isPhone(phone)) {
        aliSms.send(phone).also {
            redisCache.setCacheObject(messageRedisKey(phone), it, 5, TimeUnit.MINUTES)
        }
        Ok("发送短信验证码成功")
    } else Fail("传入正确格式手机号")


    override fun getUserAgreement(): Data<String?> = appInfoService.getOne(
        KtQueryWrapper(AppInfo::class.java).eq(AppInfo::type, 1).orderByDesc(AppInfo::createTime).last("limit 1")
    )?.run { Ok("获取用户协议成功", text) } ?: Fail(201, "暂未添加用户协议")

    override fun getPrivacyPolicy(): Data<String?> = appInfoService.getOne(
        KtQueryWrapper(AppInfo::class.java).eq(AppInfo::type, 2).orderByDesc(AppInfo::createTime).last("limit 1")
    )?.run { Ok("获取隐私政策成功", text) } ?: Fail(201, "暂未添加隐私政策")

    /**
     * 通用token构建器
     */
    private val tokenGenerator: (String) -> String = {
        securityManager.login(TokenProfile().apply { id = it })
    }

}